package com.hzgj.soa.spring.corr;

import com.google.common.collect.Sets;
import com.hzgj.bcl.soa.cicada.pool.ChannelPoolConfig;
import com.hzgj.bcl.soa.config.ReferenceDef;
import com.hzgj.bcl.soa.config.ServerDef;
import com.hzgj.bcl.soa.config.ServiceDef;
import com.hzgj.bcl.soa.rpc.server.ServerConfig;
import com.hzgj.soa.spring.ConsumerConfig;
import com.hzgj.soa.spring.ServiceConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;

import java.util.Set;

public class SpringConfigCheckProcessor {

    private Logger logger = LoggerFactory.getLogger(getClass());

    public void process(DefaultListableBeanFactory beanFactory) throws BeansException {
        handleConfig(beanFactory, ReferenceDef.class, "consumer", beanFactory.getBeanNamesForType(ConsumerConfig.class));
        handleConfig(beanFactory, ReferenceDef.class, "pool", beanFactory.getBeanNamesForType(ChannelPoolConfig.class));
        handleServerPoolAttr(beanFactory);
        handleServerAttr(beanFactory);
    }

    private void handleServerPoolAttr(DefaultListableBeanFactory beanFactory) {
        String[] serverNames = beanFactory.getBeanNamesForType(ServerConfig.BizThreadPoolConfig.class);
        if (serverNames.length != 0) {
            Set<String> useCollection = findUse(beanFactory, ServiceDef.Attr.class, "pool");
            useCollection.addAll(findUse(beanFactory, ServerDef.class, "bizPool"));
            handleBeanDefinition(beanFactory, useCollection, serverNames);
        }
    }

    private void handleServerAttr(DefaultListableBeanFactory beanFactory) {
        String[] serverNames = beanFactory.getBeanNamesForType(ServerDef.class);
        if (serverNames.length != 0) {
            Set<String> useCollection = findUse(beanFactory, ServiceDef.Attr.class, "server");
            useCollection.addAll(findUse(beanFactory, ServiceConfig.class, "server"));
            handleBeanDefinition(beanFactory, useCollection, serverNames);
        }
    }

    private Set<String> findUse(DefaultListableBeanFactory beanFactory, Class<?> useBeanClass, String useBeanProperty) {
        String[] names = beanFactory.getBeanNamesForType(useBeanClass);
        Set<String> useCollection = Sets.newHashSet();
        for (String name : names) {
            BeanDefinition beanDefinition = beanFactory.getBeanDefinition(name);
            PropertyValue propertyValue = beanDefinition.getPropertyValues().getPropertyValue(useBeanProperty);
            if (propertyValue != null) {
                useCollection.add(propertyValue.getValue().toString());
            }
        }
        return useCollection;
    }

    private void handleConfig(DefaultListableBeanFactory beanFactory, Class<?> useBeanClass, String useBeanProperty, String[] configNames) {
        if (configNames.length != 0) {
            handleBeanDefinition(beanFactory, findUse(beanFactory, useBeanClass, useBeanProperty), configNames);
        }
    }

    private void handleBeanDefinition(DefaultListableBeanFactory beanFactory, Set<String> useCollection, String[] configNames) {
        if (useCollection.size() == 0) {
            for (String name : configNames) {
                beanFactory.removeBeanDefinition(name);
                logger.warn("remove beanDefinition of " + name);
            }
        } else {
            for (String name : configNames) {
                if (!useCollection.contains(name)) {
                    beanFactory.removeBeanDefinition(name);
                    logger.warn("remove beanDefinition of " + name);
                }
            }
        }
    }
}